<template>
    <div class="drag-box" :draggable="draggable" ref="dragNode" :style="styleObj">
        <slot>
            <span>拽我</span>
        </slot>
    </div>
</template>


<script>
export default {
    props: {
        draggable: {
            type: Boolean,
            default: true
        },
        left: {
            type: [String, Number],
            default: ""
        },
        right: {
            type: [String, Number],
            default: ""
        },
        top: {
            type: [String, Number],
            default: ""
        },
        bottom: {
            type: [String, Number],
            default: ""
        },
        zIndex: {
            type: [String, Number],
            default: 99
        }
    },
    data() {
        return {
            mode: "init",//模式，初始状态init和拖动后的状态
            pageX: 0,
            pageY: 0,

            x0: 0,
            y0: 0,
        }
    },
    mounted() {
        this.pageX = this.$refs.dragNode.offsetLeft
        this.pageY = this.$refs.dragNode.offsetTop
        // 初始化拖拽
        this.initDrag()
    },
    beforeDestroy(){
        //移除事件监听
       this.$refs.dragNode.ondragstart = null
       this.$refs.dragNode.ondragend = null
       this.$refs.dragNode.ondrag = null
    },
    watch: {
        top(newVal, oldVal) {
            // 监听位置变动
            this.handlePositionChange()
        },
        left(newVal, oldVal) {
            // 监听位置变动
            this.handlePositionChange()
        },
        bottom(newVal, oldVal) {
            // 监听位置变动
            this.handlePositionChange()
        },
        right(newVal, oldVal) {
            // 监听位置变动
            this.handlePositionChange()
        },
    },
    methods: {
        // 初始化拖拽
        initDrag() {
            const vm = this
            // 监听拖拽开始，记录被拖拽的元素
            this.$refs.dragNode.ondragstart = function (e) {
                // 修改通明度
                e.target.style.opacity = 0.5
                // 记录起始位置
                vm.x0 = e.pageX
                vm.y0 = e.pageY
            }
            // 监听拖拽结束
            this.$refs.dragNode.ondragend = function (e) {
                // 记录模式
                vm.mode = 'drag'
                // 记录最新坐标
                var distanceX = e.pageX - vm.x0
                var distanceY = e.pageY - vm.y0
                vm.pageX += distanceX
                vm.pageY += distanceY
                // 恢复透明度
                e.target.style.opacity = 1
            }
            // 监听拖拽结束
            this.$refs.dragNode.ondrag = function (e) {
                // 这种不做处理
                if(e.pageX == 0 && e.pageY == 0){

                }else{
                    // 记录模式
                    vm.mode = 'drag'
                    // 计算移动距离
                    var distanceX = e.pageX - vm.x0
                    var distanceY = e.pageY - vm.y0
                    // 更新最新坐标
                    vm.pageX += distanceX
                    vm.pageY += distanceY
                    // 记录起始位置
                    vm.x0 = e.pageX
                    vm.y0 = e.pageY
                }
            }
        },
        // 监听位置变动
        handlePositionChange(){
            // 重置模式
            this.mode = 'init'
            // 渲染完毕后，更新位置参数
            this.$nextTick(()=>{
                this.pageX = this.$refs.dragNode.offsetLeft
                this.pageY = this.$refs.dragNode.offsetTop
            })
        },
        //节流
        throttle(cb, delay) {
            //记录上次回调执行时的时间戳
            var prev = 0
            //定义内部函数并返回，形成闭包，缓存prev
            return function () {
                //事件触发时上下文
                var context = this
                //事件触发时的参数
                var args = arguments
                //对比时间差 超过时间间隔则执行回调
                if (Date.now() - prev >= delay) {
                    //执行回调（绑定this，传递参数）
                    cb && cb.apply(context, args)
                    //更新prev
                    prev = Date.now()
                }
            }
        }
    },
    computed: {
        styleObj(){
            // 初始模式，按照top/bottom/left/right决定位置
            if(this.mode == 'init'){
                return {
                    zIndex: this.zIndex,
                    bottom: this.bottom,
                    top: this.top,
                    right: this.right,
                    left: this.left
                }
            }else{
                // 推拽后的模式，按照pageX/pageY决定位置
                return {
                    zIndex: this.zIndex,
                    top: this.pageY + 'px',
                    left: this.pageX + 'px'
                }
            }
        }
    }
}
</script>

<style scoped>
.drag-box {
    position: fixed;
}
</style>